from typing import *
import functools
# class Person:
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#
#
# person = Person("Evan", "18")
# print(person.name)
# print(person.age)


class Pet:
    __life = "moving"


class Dog(Pet):
    __life = "barking"


dog = Dog()
# print(dog._Dog__life)
# print(dog._Pet__life)

#print(person.age)


class Room:
    def __init__(self, length, width, high):
        self.length = length
        self.width = width
        self.high = high

    def area(self):
        return self.length * self.width

    @property
    def volume(self):
        return self.length * self.width * self.high


# home = Room(1, 2, 3)
# print(home.area())
# print(home.volume)  # 使用特性，遵循统一访问原则
#
# home.volume = 1


class Person:
    def __init__(self, name, age):
        self.name = name
        self.__age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, value):
        if not isinstance(value, int):
            raise TypeError("年龄必须是整数")
        self.__age = value

#
# p = Person("HaiWang", 18)
# p.age = "abc"


# # "test.txt":你好，世界
# with open("test.txt", 'rb') as f:
#     line = f.readline()
#     print(type(line))
#     print(line)
#
# text = "hello,world"
# # text = "你好，世界"
# b_text = bytes(text, encoding='utf-8')
# print(type(b_text))
# print(b_text)
#
# text = str(b_text, encoding='ascii')
# print(text)


# # 1. 索引
# str = "abc"
# print(str[0])
# print(str[-2])
# print(str[-1])
# # 2. 切片
# list = ['a', 'b', 'c']
# print(list[0:-1])
# print(list[:])
# # 3. 相加
# tuple_a = ('a', 'b', 'c')
# tuple_b = ('d', 'e')
# tuple_a_b = tuple_a + tuple_b
# print(tuple_a_b)
# print(type(('a',))) # 元组里只有一个元素时，会被认为是该元素的类型
# # 4. 相乘
# print(tuple_a_b * 2)
# # 5. 包含 in
# _dict = {"a": 1, "b": 2}
# print('a' in _dict)
# print(_dict['a'])

# _str = ""
# _list = []
# print(_str==_list)

class Hello:
    def __len__(self):
        return 0


class World:
    def __bool__(self):
        return False

#
# hello = Hello()
# world = World()
# print(bool(hello))
# print(bool(world))

# a = 0
# print(dir(a))  # dir返回对象的属性和方法列表，不带参数返回当前范围内的变量、方法和定义的类型列表
# print(bool(a))

# _str = ""
# print(dir(_str))
# print(bool(_str))
#
#
# # 字典推导式，对换key,value
# _dict = {"a": 1, "b": 2}
# _dict = {v: k for k, v in _dict.items()}
# print(_dict)


# 集合推导式跟列表推导式非常相似，唯一区别在于用 { } 代替 [ ]
# _set = {x for x in range(10) if x % 2 == 0}
# print(_set)


def add(x, y):
    """
    Get the value of a plus B
    :param x:int, float
    :param y:int, float
    :return:int, float
    """
    return x + y


def odd(x: int) -> int:
    return x**2


def student(name: str, age: int, sex: str = '男') -> str:
    return f"患者：{name}\n年龄：{age}\n性别：{sex}"


# print(student("小李", 24.1))


class Animal:
    def run(self):
        print(f'animal alawys run! {self.name}')


class Dog:
    # 创建的就是代表实例的self
    def __new__(cls, *args, **kwargs):
        # 此处返回Animal实例
        return object.__new__(Animal, *args, **kwargs)

    def run(self):
        print('dog run! {self.name}')


# list
def list_to_str(list: List[str], separator: str = "") -> str:
    return separator.join(list)


# _list = ["1", "+", "1.5", "=", "2.5"]
# print(list_to_str(_list))

def get_name(person: Tuple[str, int, float] = ("小明", 21, 1.80)) -> None:
    print(f"name:{person[0]}")

# get_name(1)


# 根据官方文档，Dict 推荐用于注解返回类型，Mapping 推荐用于注解参数
def size(rect: Mapping[str, int]) -> Dict[str, int]:
    return {'width': rect['width'] + 100, 'height': rect['width'] + 100}


# _dict = {'width': 100}
# print(size(_dict))

# set ,Set 推荐用于注解返回类型，AbstractSet 用于注解参数(collections.abc.Set 的泛型)
def describe(s: AbstractSet[int]) -> Set[int]:
    return set(s)

#
# b', 1, 2}
# print(describe(_set))


# Sequence
def square(elements: Sequence[float]) -> List[float]:
    return [x ** 2 for x in elements]


# print(square([1, 2, 3]))


# NoReturn
def hello() -> NoReturn:
    print('hello')


def out(a: Any) -> NoReturn:
    print(a)


height = 1.75
Height = TypeVar('Height', int, float, None)


def get_height() -> Height:
    return height

# print(get_height())


def date(year: int, month: int, day: int) -> str:
    return f'{year}-{month}-{day}'


def get_date_fn() -> Callable[[int, int, int], str]:
    return date

print(get_date_fn()(1, 1, 1))


def echo_round() -> Generator[int, float, str]:
    yield 0
    yield 1.87
    yield "ok"


for i in echo_round():
    print(i)

# dict是根据key来排序
print(sorted({1: "1", 2: "2"}, key=abs))
# 元组
print(sorted((1, 2), key=abs))
# 列表
print(sorted([1, 2], key=abs))
# 集合
print(sorted({1, 2}, key=abs))
# 字符串
print(sorted("21", key=int))


def say(a, b, c, d, e):
    return a + b + c + d + e


say_hi = functools.partial(say, a="s", b="a", c="y")
print(say_hi(d="h", e="i"))

say_hi = functools.partial(say, d="h", e="i")
print(say_hi('s', 'a', 'y'))


g = (i for i in range(10))
print(type(g))